const merge_img_gap = 16;

/**
 * 创建 Canvas
 * @param {number} width 宽
 * @param {number} height 高
 * @param {number} ratio 缩放比
 * @param {number} globalAlpha 透明度
 * @returns {Array}
 */
const prepareCanvas = (
    width,
    height,
    ratio = 1,
    globalAlpha = 1,
) => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const realWidth = width * ratio;
    const realHeight = height * ratio;
    canvas.setAttribute('width', `${realWidth}px`);
    canvas.setAttribute('height', `${realHeight}px`);
    ctx.globalAlpha = globalAlpha;
    ctx.save();
    return [ctx, canvas, realWidth, realHeight];
}
/**
 * @param {string | Array} content 内容
 * @returns {Array}
 */
const getContent = (content) => {
    if (Array.isArray(content)) {
        return content.filter(Boolean);
    }
    else if (typeof content === 'string') {
        return [content];
    }
    return [];
}
/**
 * 字体大小、行高
 * @param {Array} content 内容
 * @param {*} width 宽
 * @param {*} fontSize 
 * @returns {Array}
 */
const getFZ = (content, width, fontSize) => {
    let fz = fontSize;
    if (!fz) {
        const childLength = content.map(s => s.length);
        const maxLength = Math.max(...childLength);
        fz = Math.floor(width / maxLength);
    }
    if (fz < 10) {
        fz = 10;
    }
    // 每行之间的距离（包括字体高度）
    const lineHeight = fz * 1.2;
    return [
        fz,
        lineHeight,
    ];
}

const getContentOriginImg = ({
    content,
    canvasWidth,
    fontSize,
    fontFamily,
    textAlign,
    textBaseline,
    dpr,
}) => {
    if (!content.length) {
        return '';
    }
    // console.log({ content, canvasWidth, fontSize })
    const length = content.length;
    const [fz, lineHeight] = getFZ(content, canvasWidth, fontSize);
    // console.log({ fz, lineHeight })
    // 总高度
    const totalHeight = length * lineHeight;
    const [ctx, canvas, contentWidth, contentHeight] = prepareCanvas(canvasWidth, totalHeight, dpr);
    // 计算垂直居中的起始位置
    const startY = contentHeight / (length * 2);
    // 绘制文本
    let y = startY;
    const x = canvasWidth / 2;
    content.forEach((text) => {
        ctx.font = [`${fz}px`, fontFamily].filter(Boolean).join(' ');
        ctx.textAlign = textAlign;
        ctx.textBaseline = textBaseline;
        ctx.fillText(text, x, y);
        y += lineHeight;
    })
    ctx.save();

    const imgUrl = canvas.toDataURL();

    // @Test
    // const img = document.createElement('img');
    // img.src = imgUrl;
    // img.style.border = '2px solid red';
    // document.body.appendChild(img);

    return imgUrl;
}

const loadImage = async (src) => {
    return new Promise((res) => {
        const img = document.createElement('img');
        img.setAttribute('crossOrigin', 'anonymous');
        img.src = src;
        img.onload = () => res(img);
        img.onerror = () => res();
    })
}

const mergeImage = async (imgUrls, {
    width,
    gap
}) => {
    const [wGap, hGap] = gap;
    let images = await Promise.all(imgUrls.filter(Boolean).map((url) => loadImage(url)));
    let totalHeight = merge_img_gap + hGap * 2;
    images = images.filter(Boolean).map((img) => {
        const realWidth = img.width;
        const realHeight = img.height;
        const ratio = width / realWidth;
        const height = Math.floor(realHeight * ratio);
        totalHeight += height;
        const rc = {
            img,
            realWidth,
            realHeight,
            width,
            height,
        };
        return rc;
    })
    const [ctx, canvas, contentWidth, contentHeight] = prepareCanvas(
        width + wGap * 2,
        totalHeight
    );
    if (images.length) {
        let x = wGap;
        let y = hGap;
        images.forEach(({
            img,
            width,
            height,
        }) => {
            ctx.imageSmoothingQuality = 'high';
            ctx.drawImage(img, x, y, width, height);
            y += merge_img_gap + height;
        });
    }
    else {
        return [];
    }
    // @Test
    // document.body.appendChild(canvas);

    return [ctx, canvas, contentWidth, contentHeight];
}

const createWatermarkImg = async ({
    content,
    width,
    fontSize,
    fontFamily,
    textAlign,
    textBaseline,
    dpr,
    img,
    globalAlpha,
    angle,
    gap
}) => {
    const contentImg = getContentOriginImg({
        content,
        canvasWidth: width,
        fontSize,
        fontFamily,
        textAlign,
        textBaseline,
        dpr,
        angle,
    });
    // console.log(contentImg);

    const [ctx, canvas, contentWidth, contentHeight] = await mergeImage([img, contentImg], {
        width,
        gap
    });
    if (ctx) {
        const maxSize = Math.max(contentWidth, contentHeight);
        const [rCtx, rCanvas, realMaxSize] = prepareCanvas(maxSize, maxSize, dpr, globalAlpha);

        // Copy from `ctx` and rotate
        rCtx.translate(realMaxSize / 2, realMaxSize / 2);
        rCtx.rotate(angle);
        rCtx.drawImage(canvas, -contentWidth / 2, -contentHeight / 2);
        // @Test
        // document.body.appendChild(rCanvas);
        return rCanvas.toDataURL();
    }
    return '';
}

/**
 * Watermark
 */
class Watermark {
    watermark_mask_el = null
    createWatermarkMaskTimer = 0
    resize_observer = null
    mutation_observer = null

    constructor() {
    }

    createWatermarkMask = ({
        img,
        container,
        zIndex,
        width,
    }) => {
        const w = container.offsetWidth;
        const h = container.offsetHeight;
        if (this.watermark_mask_el) {
            this.watermark_mask_el.remove();
            this.watermark_mask_el = null;
        }
        this.watermark_mask_el = document.createElement('div');
        this.watermark_mask_el.setAttribute('style', `
            position:absolute;
            top:0;
            left:0;
            width:${w}px;
            height:${h}px;
            z-index:${zIndex};
            pointer-events:none;
            background-repeat:repeat;
            background-image:url('${img}');
            background-size: ${width}px auto;
        `);
        container.appendChild(this.watermark_mask_el);
    }

    resize_observer_disconnect() {
        if (this.resize_observer) {
            this.resize_observer.disconnect();
            this.resize_observer = null;
        }
    }

    mutation_observer_disconnect = () => {
        if (this.mutation_observer) {
            this.mutation_observer.disconnect();
            this.mutation_observer = null;
        }
    }

    createWatermarkMaskFactor = (...args) => {
        clearTimeout(this.createWatermarkMaskTimer);
        this.createWatermarkMaskTimer = setTimeout(() => this.createWatermarkMask(...args), 500);
    }


    async createWatermark(opts = {}) {
        const container = opts.container;
        const width = opts.width || 200;
        const angle = (+opts.angle || -45) * (Math.PI / 180);
        const zIndex = opts.zIndex || 100;
        const globalAlpha = opts.globalAlpha || 1;
        const dpr = opts.dpr || 1;
        const gap = (opts.gap || [50, 50]).map((v) => +v || 0);
        const content = getContent(opts.content);
        const fontSize = opts.fontSize || 20;
        const fontFamily = opts.fontFamily || 'OpenSans ExtraBold';
        const textAlign = opts.textAlign || 'center';
        const textBaseline = opts.textBaseline || 'middle';
        const img = opts.img;
        const watermark_img = await createWatermarkImg({
            content,
            width,
            fontSize,
            fontFamily,
            textAlign,
            textBaseline,
            dpr,
            img,
            globalAlpha,
            angle,
            gap,
        });
        // @Test
        // const imgDom = document.createElement('img');
        // imgDom.src = watermark_img;
        // imgDom.style.border = '1px solid red';
        // document.body.appendChild(imgDom);

        const doCreateWatermarkMask = () => {
            this.createWatermarkMaskFactor({
                img: watermark_img,
                container,
                zIndex,
                width,
            });
        }
        {
            if (!this.resize_observer) {
                this.resize_observer = new ResizeObserver(([entrie]) => {
                    // console.log(entrie);
                    doCreateWatermarkMask();
                })
                this.resize_observer.observe(container);
            }
        }

        {
            this.mutation_observer_disconnect();
            const observerCallback = (mutationsList, observer) => {
                for (const mutation of mutationsList) {
                    // console.log('mutation', mutation, 'mutation.type', mutation.type);
                    if (mutation.type === 'childList') {
                        for (const el of mutation.removedNodes) {
                            if (el === this.watermark_mask_el) {
                                // console.log('删除了');
                                doCreateWatermarkMask();
                            }
                        }
                    } else if (mutation.type === 'attributes') {
                        if (mutation.target === this.watermark_mask_el) {
                            console.log('属性改变了');
                            doCreateWatermarkMask();
                        }
                    }
                }
            }
            this.mutation_observer = new MutationObserver(observerCallback);
            this.mutation_observer.observe(container, {
                childList: true, // 观察目标子节点的变化，是否有添加或者删除
                attributes: true, // 观察属性变动
                subtree: true, // 观察后代节点，默认为 false
            });
        }
    }

    destroyWatermark() {
        this.resize_observer_disconnect();
        this.mutation_observer_disconnect();
    }
}

export {
    Watermark
};